package com.dkd.manage.task.allocator.algorithm;

import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Slf4j
public class TabuSearchSelector {
    private int tabuTenure = 5;
    private int maxIterations = 50;

    public Long select(Map<Long, Double> scores, List<Long> candidateIds) {
        log.info("开始禁忌搜索选择，候选人数: {}", candidateIds.size());

        if (candidateIds.isEmpty()) {
            return null;
        }

        Queue<Long> tabuList = new LinkedList<>();
        Long currentSolution = candidateIds.get((int) (Math.random() * candidateIds.size()));
        Long bestSolution = currentSolution;
        double bestScore = scores.getOrDefault(bestSolution, 0.0);

        for (int iter = 0; iter < maxIterations; iter++) {
            // 生成邻域
            List<Long> neighborhood = generateNeighborhood(currentSolution, candidateIds, tabuList);

            if (neighborhood.isEmpty()) {
                break;
            }

            // 选择邻域中最优解
            Long nextSolution = neighborhood.stream()
                    .max(Comparator.comparingDouble(empId -> scores.getOrDefault(empId, 0.0)))
                    .orElse(currentSolution);

            double nextScore = scores.getOrDefault(nextSolution, 0.0);

            // 更新当前解
            currentSolution = nextSolution;

            // 更新禁忌表
            tabuList.offer(currentSolution);
            if (tabuList.size() > tabuTenure) {
                tabuList.poll();
            }

            // 更新全局最优
            if (nextScore > bestScore) {
                bestSolution = currentSolution;
                bestScore = nextScore;
            }

            log.debug("禁忌搜索第 {} 代，当前最优评分: {}", iter + 1, bestScore);
        }

        log.info("禁忌搜索选择完成，选择员工: {}", bestSolution);
        return bestSolution;
    }

    private List<Long> generateNeighborhood(Long current, List<Long> candidates, Queue<Long> tabuList) {
        return candidates.stream()
                .filter(candidate -> !candidate.equals(current))
                .filter(candidate -> !tabuList.contains(candidate))
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
    }
}